package com.example.his.api.common;

import com.example.his.api.exception.HisException;
import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.io.InputStream;

@Component
@Slf4j
public class MinioUtil {

  @Value ( "${minio.endpoint}" )
  private String endpoint;

  @Value ( "${minio.access-key}" )
  private String accessKey;

  @Value ( "${minio.secret-key}" )
  private String secretKey;

  @Value ( "${minio.bucket}" )
  private String bucket;

  private MinioClient client;

  @PostConstruct
  public void init() {
    // 打印 endpoint 确认端口正确
    log.info( "Initializing MinIO Client with endpoint: {}", endpoint );

    // 确保 endpoint 使用 API 端口 (9000)，不是 Console 端口
    if ( endpoint.contains( ":9001" ) ) {
      log.error( "MinIO endpoint 配置错误，不能使用 Console 端口 (9001)，请改为 API 端口 (9000)" );
      throw new RuntimeException( "MinIO endpoint 配置错误，应使用 API 端口" );
    }

    this.client = MinioClient.builder()
        .endpoint( endpoint )
        .credentials( accessKey, secretKey )
        .build();

    log.info( "MinIO Client 初始化完成" );
  }

  public void uploadImage( String path, MultipartFile file ) {
    try {
      // 上传文件 (最大5M)
      this.client.putObject(
          PutObjectArgs.builder()
              .bucket( bucket )
              .object( path )
              .stream( file.getInputStream(), file.getSize(), -1 )
              .contentType( file.getContentType() != null ? file.getContentType() : "application/octet-stream" )
              .build()
      );
      log.debug( "文件已保存到 MinIO，路径：{}", path );
    }
    catch ( Exception e ) {
      log.error( "保存文件失败", e );
      throw new HisException( "保存文件失败" );
    }
  }

  /**
   * 上传Excel文件到MinIO
   *
   * @param path 文件存储路径
   * @param file 要上传的Excel文件
   * @throws HisException 文件上传失败时抛出异常
   */
  public void uploadExcel( String path, MultipartFile file ) {
    try {
      // Excel文件的MIME类型
      String mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
      // Excel文件不能超过20M
      this.client.putObject( PutObjectArgs.builder()
          .bucket( bucket )
          .object( path )
          .stream( file.getInputStream(), file.getSize(), 20 * 1024 * 1024 )
          .contentType( mimeType )
          .build() );
      log.debug( "向{}保存了文件", path );
    }
    catch ( Exception e ) {
      log.error( "保存文件失败", e );
      throw new HisException( "保存文件失败" );
    }
  }

  /**
   * 从MinIO下载文件
   *
   * @param path 文件在MinIO中的存储路径
   * @return 文件的输入流，用于读取文件内容
   * @throws HisException 文件下载失败时抛出异常
   */
  public InputStream downloadFile( String path ) {
    try {
      // 构建下载对象的参数
      GetObjectArgs args = GetObjectArgs.builder()
          .bucket( bucket )
          .object( path )
          .build();

      // 执行下载操作并返回文件输入流
      return this.client.getObject( args );
    }
    catch ( Exception e ) {
      log.error( "下载文件失败", e );
      throw new HisException( "下载文件失败" );
    }
  }

  /**
   * 从MinIO存储中删除指定路径的文件
   *
   * @param path 文件在MinIO中的存储路径
   * @throws HisException 文件删除失败时抛出异常
   */
  public void deleteFile(String path) {
    try {
      // 构建删除对象的参数，指定存储桶和文件路径
      this.client.removeObject(
          RemoveObjectArgs.builder()
              .bucket(bucket)
              .object(path)
              .build()
      );
      // 记录删除成功的日志信息
      log.debug("文件删除成功，路径：{}", path);
    }
    catch (Exception e) {
      // 记录删除过程中发生的异常信息
      log.error("删除文件失败", e);
      // 抛出自定义异常，通知调用方删除操作失败
      throw new HisException("删除文件失败");
    }
  }
}
